package my.p2p.tcp;

import io.netty.buffer.ByteBuf;
import io.netty.buffer.Unpooled;
import io.netty.channel.Channel;
import io.netty.channel.ChannelHandler;
import io.netty.channel.ChannelHandlerContext;
import io.netty.channel.SimpleChannelInboundHandler;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.net.InetSocketAddress;
import java.nio.charset.StandardCharsets;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;

/**
 * @author fengbo
 */
@ChannelHandler.Sharable
public class EchoServerHandler extends SimpleChannelInboundHandler<ByteBuf> {

    private static final Logger log = LoggerFactory.getLogger(EchoServerHandler.class);

    private Map<String, Channel> channels = new ConcurrentHashMap<>(16);

    @Override
    public void channelRead0(ChannelHandlerContext ctx, ByteBuf msg) {
        byte[] req = new byte[msg.readableBytes()];
        msg.readBytes(req);
        String body = new String(req, StandardCharsets.UTF_8);
        log.info(body);
        if ("quit".equals(body)) {
            ctx.close();
            return;
        }
        if ("list".equals(body)) {
            sendMsgToChannel(ctx);
            return;
        }
        InetSocketAddress socketAddress = (InetSocketAddress) ctx.channel().remoteAddress();
        Channel channel = channels.get(body);
        if (channel == null) {
            ctx.pipeline().writeAndFlush(Unpooled.copiedBuffer("连接地址不存在\n".getBytes()));
        } else {
            String address = socketAddress.getHostString() + "::" + socketAddress.getPort();
            ctx.pipeline().writeAndFlush(Unpooled.copiedBuffer(
                    ("ok::" + body + "::" + address + "\n").getBytes()));
            channel.pipeline().writeAndFlush(Unpooled.copiedBuffer(
                    ("ok::" + address + "::" + body + "\n").getBytes()));
        }
    }

    @Override
    public void channelActive(ChannelHandlerContext ctx) {
        InetSocketAddress socketAddress = (InetSocketAddress) ctx.channel().remoteAddress();
        log.info("Socket [{}] active", socketAddress.getHostString());
        sendMsgToChannel(ctx);
        String key = socketAddress.getHostString() + "::" + socketAddress.getPort();
        channels.put(key, ctx.channel());
        ctx.fireChannelActive();
    }

    @Override
    public void channelInactive(ChannelHandlerContext ctx) {
        InetSocketAddress socketAddress = (InetSocketAddress) ctx.channel().remoteAddress();
        log.info("Socket [{}] inactive", socketAddress.getHostString());
        String key = socketAddress.getHostString() + "::" + socketAddress.getPort();
        channels.remove(key);
        ctx.fireChannelUnregistered();
    }

    @Override
    public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) {
        cause.printStackTrace();
        ctx.close();
    }

    private void sendMsgToChannel(ChannelHandlerContext ctx) {
        InetSocketAddress socketAddress = (InetSocketAddress) ctx.channel().remoteAddress();
        String key = socketAddress.getHostString() + "::" + socketAddress.getPort();
        for (String address : channels.keySet()) {
            if (!key.equals(address)) {
                ctx.pipeline().writeAndFlush(Unpooled.copiedBuffer((address + "\n").getBytes()));
            }
        }
    }
}